package com.fzu.geometa.validate.service;

import com.fzu.geometa.validate.common.Const;
import com.fzu.geometa.validate.dao.TestParameters;
import org.apache.commons.io.FileUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.testng.TestNG;
import org.testng.xml.*;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.fzu.geometa.validate.common.Const.*;

@Service
public class TestExecService {
    @Value("${test-output}")
    private String testOutput;

    public void ExecuteTest(TestParameters p, String id) {
        Path path = Paths.get(testOutput, id);
        TestNG testNG = getTestNG(p.getTestName(), p.getTestUrl(), p.getDataType(),path.toString());
        testNG.run();
        try {
            modifyPage(id,p.getDataType());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private TestNG getTestNG(String testName, String testUrl, String dataType, String outputPath) {
        // 定义测试套件
        XmlSuite suite = new XmlSuite();
        suite.setName("ISO 19163-2");
        suite.setVerbose(1);
        suite.setFileName("Test definition");

        // 设置参数
        Map<String,String> parameter = new HashMap<>();
        parameter.put("test-url",testUrl);
        suite.setParameters(parameter);

        // 定义测试
        List<XmlTest> tests = new ArrayList<>();
        XmlTest test = new XmlTest(suite);
        test.setName(testName);

        // 设置测试组
        XmlGroups group = new XmlGroups();
        XmlRun run = new XmlRun();
        run.onInclude(dataType);
        group.setRun(run);
        test.setGroups(group);

        // 设置测试类
        List<XmlClass> classes = new ArrayList<>();
        XmlClass xmlClass = new XmlClass(Const.ISO_19163_TEST_CLASS);
        classes.add(xmlClass);
        test.setClasses(classes);

        // 添加测试
        tests.add(test);
        suite.setTests(tests);

        // 设置监听器
        List<String> listeners = new ArrayList<>();
        listeners.add(REPORTER_CLASS);
        listeners.add(TEST_LISTENER_CLASS);
        listeners.add(EXECUTION_LISTENER_CLASS);
        suite.setListeners(listeners);

        System.out.println(suite.toXml());

        // 添加测试套件
        TestNG testNG = new TestNG();
        testNG.setCommandLineSuite(suite);

        // 设置输出路径
        testNG.setOutputDirectory(outputPath);

        // 不启用默认监听类
        testNG.setUseDefaultListeners(false);

        // 返回 TestNG 类
        return testNG;
    }

    private void modifyPage(String curPath,String dataType) throws IOException {

        // 添加返回主页链接
        Path path = Paths.get(testOutput, curPath, "html", "suites.html");
        File file = new File(path.toString());
        Document doc = Jsoup.parse(file, Charset.defaultCharset().name());
        Element body = doc.body();
        body.append("<br/>");
        body.append("<div><p align='right'><a href='../../../../index' target='_top'>Back</a></p></div>");
        FileUtils.writeStringToFile(file, doc.toString(),  Charset.defaultCharset());

        // 将结果的标题改为测试组名
        path = Paths.get(testOutput, curPath, "html", "suite1_test1_results.html");
        file = path.toFile();
        doc = Jsoup.parse(file, Charset.defaultCharset().name());
        Element h1 = doc.getElementsByTag("h1").first();
        h1.text(dataType +  " (Based on ISO 19163-2)");
        FileUtils.writeStringToFile(file, doc.toString(),  Charset.defaultCharset());

        // jar包运行模式下，overview.html 会编码错误，但在 IDE 中运行没有编码错误。
        // 将 GBK 编码改为 UTF-8 （可能是在 IDE 中默认编码是 UTF-8，外部运行时采用了系统的默认的 GBK 编码）
        if (Charset.defaultCharset().name().equals("GBK")) {
            path = Paths.get(testOutput, curPath, "html", "overview.html");
            file = path.toFile();
            byte[] bytes = FileUtils.readFileToByteArray(file);
            String content = new String(bytes, "GBK");
            FileUtils.write(file,content, StandardCharsets.UTF_8);
            System.out.println("Default charset: GBK" );
            System.out.println("Update 'overview.html' to UTF-8");
        }
    }
}
